﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml.Linq;

using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.VersionControl.Client;

namespace NewFeatureGuidsConsoleApplication
{
    class Program
    {
        private const string LogPath = @"C:\Temp\";
        private const string LogFile = "NewFeatureGuidsLog.txt";
        private static string RootPath = @"C:\Development\Source\MySolution\";


        static void Main(string[] args)
        {
            if (args != null && args.Any())
            {
                // for debug purposes, open this projects properties, click Debug tab and enter Command line arguments
                RootPath = args[0];
            }

            GetFeatures();

            Console.WriteLine("Conversion finished");
            Console.Read();
        }

        static void GetFeatures()
        {
            var directoryInfo = new DirectoryInfo(RootPath);
            var files = directoryInfo.GetFiles("*.feature", SearchOption.AllDirectories);

            foreach (var file in files)
            {
                GetFeature(file);
            }
        }

        private static void GetFeature(FileInfo fileInfo)
        {
            try
            {
                var featureFile = XDocument.Load(fileInfo.FullName);

                var featureId = featureFile.Root != null
                                    ? featureFile.Root.Attributes().FirstOrDefault(x => x.Name == "featureId")
                                    : new XAttribute(string.Empty, string.Empty);

                var id = featureFile.Root != null
                             ? featureFile.Root.Attributes().FirstOrDefault(x => x.Name == "Id")
                             : new XAttribute(string.Empty, string.Empty);

                var oldGuid = featureId.Value;

                var newGuid = Guid.NewGuid().ToString();

                var logText = string.Format(
                    "FEATURE    old feature guid -> new feature guid: {0} -> {1}, file: {2}{3}",
                    oldGuid,
                    newGuid,
                    fileInfo.FullName,
                    Environment.NewLine);

                Directory.CreateDirectory(LogPath);
                File.AppendAllText(LogPath + LogFile, logText);

                featureId.Value = newGuid;
                id.Value = newGuid;

                fileInfo.IsReadOnly = false;

                if (GetReferencedFiles(RootPath, oldGuid, newGuid))
                {

                    var workspaceInfo = Workstation.Current.GetLocalWorkspaceInfo(fileInfo.FullName);
                    var server = new TfsTeamProjectCollection(workspaceInfo.ServerUri);
                    var workspace = workspaceInfo.GetWorkspace(server);

                    workspace.PendEdit(fileInfo.FullName);
                    featureFile.Save(fileInfo.FullName);
                }
            }
            catch (Exception ex)
            {
                File.AppendAllText(LogPath + LogFile, ex.Message + Environment.NewLine);
                Console.WriteLine(ex.Message);
            }
        }

        private static bool GetReferencedFiles(string rootPath, string guidToReplace, string newGuid)
        {
            try
            {
                var directoryInfo = new DirectoryInfo(rootPath);
                var xmlFiles =
                    directoryInfo.GetFiles("*.*", SearchOption.AllDirectories)
                        .Where(
                            x =>
                            !x.Name.EndsWith(".dll", StringComparison.OrdinalIgnoreCase)
                            && !x.Name.EndsWith(".pdb", StringComparison.OrdinalIgnoreCase)
                            && !x.Name.EndsWith(".feature", StringComparison.OrdinalIgnoreCase));

                foreach (var fileInfo in xmlFiles)
                {
                    try
                    {
                        ReadOrdinaryFile(fileInfo, guidToReplace, newGuid);
                    }
                    catch (Exception ex)
                    {
                        File.AppendAllText(LogPath + LogFile, string.Format("{0}, {1}{2}", fileInfo.Name, ex.Message, Environment.NewLine));
                        Console.WriteLine(ex.Message);
                        return false;
                    }
                }
            }
            catch (Exception ex)
            {
                File.AppendAllText(LogPath + LogFile, ex.Message + Environment.NewLine);
                Console.WriteLine(ex.Message);
                return false;
            }

            return true;
        }

        private static void ReadOrdinaryFile(FileInfo fileInfo, string guidToReplace, string newGuid)
        {
            var text = File.ReadAllText(fileInfo.FullName);
            
            if (text.IndexOf(guidToReplace, StringComparison.OrdinalIgnoreCase) >= 0)
            {

                var logText =
                    string.Format(
                        "REFERENCED old feature guid -> new feature guid: {1} -> {2}, file: {0}{3}",
                        fileInfo.FullName,
                        guidToReplace,
                        newGuid,
                        Environment.NewLine);
                File.AppendAllText(LogPath + LogFile, logText);

                text = Regex.Replace(text, guidToReplace, newGuid, RegexOptions.IgnoreCase);
                fileInfo.IsReadOnly = false;
                File.WriteAllText(fileInfo.FullName, text);

                var workspaceInfo = Workstation.Current.GetLocalWorkspaceInfo(fileInfo.FullName);
                var server = new TfsTeamProjectCollection(workspaceInfo.ServerUri);
                var workspace = workspaceInfo.GetWorkspace(server);

                workspace.PendEdit(fileInfo.FullName);
            }
        }
    }
}
